package net.virtuemed.jt808.util;

import lombok.extern.slf4j.Slf4j;

/**
 * BCD十六进制编码工具类
 *
 * @Description BCDUtil
 * @Author guoyb
 * @Date 2023/10/13 16:05
 */
@Slf4j
public class BCDUtil {

    public static byte[] DecimalToBCD(long num) {
        int digits = 0;
        long temp = num;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        int byteLen = digits % 2 == 0 ? digits / 2 : (digits + 1) / 2;
        byte bcd[] = new byte[byteLen];
        for (int i = 0; i < digits; i++) {
            byte tmp = (byte) (num % 10);
            if (i % 2 == 0) {
                bcd[i / 2] = tmp;
            } else {
                bcd[i / 2] |= (byte) (tmp << 4);
            }
            num /= 10;
        }
        for (int i = 0; i < byteLen / 2; i++) {
            byte tmp = bcd[i];
            bcd[i] = bcd[byteLen - i - 1];
            bcd[byteLen - i - 1] = tmp;
        }
        return bcd;
    }

    public static long BCDToDecimal(byte[] bcd) {
        return Long.valueOf(BCDUtil.BCDtoString(bcd));
    }

    public static String BCDtoString(byte bcd) {
        StringBuffer sb = new StringBuffer();
        // 高四位
        byte high = (byte) (bcd & 0xf0);
        high >>>= (byte) 4;
        high = (byte) (high & 0x0f);

        // 低四位
        byte low = (byte) (bcd & 0x0f);
        sb.append(high);
        sb.append(low);

        return sb.toString();
    }

    public static String BCDtoString(byte[] bcd) {
        StringBuffer sb = new StringBuffer();

        for (int i = 0; i < bcd.length; i++) {
            sb.append(BCDtoString(bcd[i]));
        }

        return sb.toString();
    }


    public static String parseBcdStringFromBytes(byte[] data, int startIndex, int lenth) {
        return parseBcdStringFromBytes(data, startIndex, lenth, null);
    }

    private static String parseBcdStringFromBytes(byte[] data, int startIndex, int lenth, String defaultVal) {
        try {
            byte[] tmp = new byte[lenth];
            System.arraycopy(data, startIndex, tmp, 0, lenth);
            return BCDtoString(tmp);
        } catch (Exception e) {
            log.error("解析BCD(8421码)出错:{}", e.getMessage());
            e.printStackTrace();
            return defaultVal;
        }
    }


    private static final String HEX = "0123456789ABCDEF";

    private static byte toByte(char c) {
        byte b = (byte) HEX.indexOf(c);
        return b;
    }

    /**
     * 字符串==>BCD字节数组
     *
     * @param hex
     * @return
     */
    public static byte[] toBcdBytes(String hex) {
        int len = (hex.length() / 2);
        byte[] result = new byte[len];
        char[] achar = hex.toCharArray();
        for (int i = 0; i < len; i++) {
            int pos = i * 2;
            result[i] = (byte) (toByte(achar[pos]) << 4 | toByte(achar[pos + 1]));
        }
        return result;
    }

    public static String toBcdDateString(byte[] bs) {
        if (bs.length != 3 && bs.length != 4) {
            log.error("无效BCD日期");
            return "0000-00-00";
        }
        StringBuffer sb = new StringBuffer();
        int i = 0;
        if (bs.length == 3) {
            sb.append("20");
        } else {
            sb.append(BCDUtil.BCDtoString(bs[i++]));
        }
        sb.append(BCDUtil.BCDtoString(bs[i++]));
        sb.append("-").append(BCDUtil.BCDtoString(bs[i++]));
        sb.append("-").append(BCDUtil.BCDtoString(bs[i++]));
        return sb.toString();
    }

    public static String toBcdTimeString(byte[] bs) {
        if (bs.length != 6 && bs.length != 7) {
            log.error("无效BCD时间");
            return "0000-00-00 00:00:00";
        }
        StringBuffer sb = new StringBuffer();
        int i = 0;
        if (bs.length == 6) {
            sb.append("20");
        } else {
            sb.append(BCDUtil.BCDtoString(bs[i++]));
        }
        sb.append(BCDUtil.BCDtoString(bs[i++]));
        sb.append("-").append(BCDUtil.BCDtoString(bs[i++]));
        sb.append("-").append(BCDUtil.BCDtoString(bs[i++]));
        sb.append(" ").append(BCDUtil.BCDtoString(bs[i++]));
        sb.append(":").append(BCDUtil.BCDtoString(bs[i++]));
        sb.append(":").append(BCDUtil.BCDtoString(bs[i]));
        return sb.toString();
    }


    public static String bcdToString(byte[] bcd) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bcd.length; i++) {
            int high = (bcd[i] & 0xf0) >>> 4;
            int low = bcd[i] & 0x0f;
            sb.append((char) (high + '0')).append((char) (low + '0'));
        }
        return sb.toString();
    }

    /**
     * 数字左边补齐0，使之达到指定长度。注意，如果数字转换为字符串后，长度大于size，则只保留 最后size个字符。
     *
     * @param num 数字对象
     * @param size 字符串指定长度
     * @return 返回数字的字符串格式，该字符串为指定长度。
     */
    public static final String padl(final Number num, final int size)
    {
        return padl(num.toString(), size, '0');
    }


    /**
     * 字符串左补齐。如果原始字符串s长度大于size，则只保留最后size个字符。
     *
     * @param s 原始字符串
     * @param size 字符串指定长度
     * @param c 用于补齐的字符
     * @return 返回指定长度的字符串，由原字符串左补齐或截取得到。
     */
    public static final String padl(final String s, final int size, final char c)
    {
        final StringBuilder sb = new StringBuilder(size);
        if (s != null)
        {
            final int len = s.length();
            if (s.length() <= size)
            {
                for (int i = size - len; i > 0; i--)
                {
                    sb.append(c);
                }
                sb.append(s);
            }
            else
            {
                return s.substring(len - size, len);
            }
        }
        else
        {
            for (int i = size; i > 0; i--)
            {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    /**
     * 字符串转BCD数组，比如设备id、sim卡号等
     *
     * @param s
     * @return
     */
    public static byte[] StringToBcdArr(String s) {
        if (s == null || s.length() == 0) return null;
        byte[] bytes = new byte[s.length()];
        char[] cc = s.toCharArray();
        int i = 0;
        for (char c : cc) {
            bytes[i] = (byte) (c - 0);
            i++;
        }
        return bytes;
    }
}
